package com.telit.common.service;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.telit.common.config.BaiduProperties;
import com.telit.common.entity.*;
import com.telit.common.exception.ForestBaseException;
import com.telit.common.util.CoordinateConvert;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class BaiduService {

    @Autowired
    private RestTemplate restTemplate;

    private static final String TRACK_ADDRESS = "https://api.map.baidu.com/directionlite/v1/";
    private static final String PROMPT_ADDRESS = "https://api.map.baidu.com/place/v2/";
    private static final String DETAIL_ADDRESS = "https://api.map.baidu.com/reverse_geocoding/v3";
    private static final String GEOCODING = "https://api.map.baidu.com/geocoding/v3";

    private String ak;

    public BaiduService(BaiduProperties baiduProperties) {
        ak = baiduProperties.getAk();
    }

    /**
     * 路线规划-驾车
     *
     * @param origin
     * @param destination
     * @param coord_type
     * @return
     */
    public BaiduMapInfo<Result> driving(String origin, String destination, String coord_type) {
        String[] originStr = origin.split(",");
        String[] destinationStr = destination.split(",");
        double[] originBD09 = CoordinateConvert.wgs2BD09(Double.parseDouble(originStr[0]), Double.parseDouble(originStr[1]));
        double[] destinationBD09 = CoordinateConvert.wgs2BD09(Double.parseDouble(destinationStr[0]), Double.parseDouble(destinationStr[1]));
        String orginJoin = ArrayUtil.join(originBD09, ",");
        String destinationJoin = ArrayUtil.join(destinationBD09, ",");
        Map<String, Object> paramsMap = new HashMap<>(4);
        paramsMap.put("ak", ak);
        paramsMap.put("origin", orginJoin);
        paramsMap.put("destination", destinationJoin);
        paramsMap.put("coordType", "bd09ll");
        String drivingResultStr = restTemplate.getForObject(TRACK_ADDRESS + "driving?origin={origin}&destination={destination}&ak={ak}&coord_type={coordType}", String.class, paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(drivingResultStr, BaiduMapInfo.class);

        if (baiduMapInfo.getStatus() != 0) {
            throw new ForestBaseException("路线规划-驾车出错");
        }

        JSONObject jsonResult = (JSONObject) baiduMapInfo.getResult();
        Result result = JSON.toJavaObject(jsonResult, Result.class);
        result.getRoutes().forEach(routes -> {
            routes.getSteps().forEach(steps -> {
                ArrayList<double[]> arrDou = new ArrayList<>();
                List<String> arr = Arrays.asList(steps.getPath().toString().split(";"));
                arr.forEach(s -> {
                    String[] split = s.split(",");
                    //经度 ,纬度
                    double[] bd092WGS = CoordinateConvert.bd092WGS(Double.parseDouble(split[1]), Double.parseDouble(split[0]));
                    double[] lonlatWGS = {bd092WGS[1], bd092WGS[0]};
//                    double[] a = {Double.parseDouble(split[0]),Double.parseDouble(split[1]) };
                    arrDou.add(lonlatWGS);
                });
//                List<double[]> lists = CoordinateConvert.bd09_To_gps84Array(arrDou);
                steps.setPath(arrDou);
//                steps.setPath(arrDou);
            });
        });
        baiduMapInfo.setResult(result);

        return baiduMapInfo;
        /*Map<String,Object> paramsMap = new HashMap<>(4);
        paramsMap.put("ak",ak);
        paramsMap.put("origin",origin);
        paramsMap.put("destination",destination);
        paramsMap.put("coordType",coord_type);
        String drivingResultStr = restTemplate.getForObject(TRACK_ADDRESS + "driving?origin={origin}&destination={destination}&ak={ak}&coord_type={coordType}", String.class, paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(drivingResultStr, BaiduMapInfo.class);

        if(baiduMapInfo.getStatus()!=0){
            throw new ForestBaseException("路线规划-驾车出错");
        }

        JSONObject jsonResult = (JSONObject) baiduMapInfo.getResult();
        Result result = JSON.toJavaObject(jsonResult, Result.class);
        result.getRoutes().forEach(routes -> {
            routes.getSteps().forEach(steps -> {
                ArrayList<double[]> arrDou = new ArrayList<>();
                List<String> arr = Arrays.asList(steps.getPath().toString().split(";"));
                arr.forEach(s -> {
                    String[] split = s.split(",");
                    //经度 ,纬度
                    double[] a = {Double.parseDouble(split[0]),Double.parseDouble(split[1]) };
                    arrDou.add(a);
                });
                List<double[]> lists = LongitudeLatitudeTransisteUtils.bd09_To_gps84Array(arrDou);
                steps.setPath(lists);
//                steps.setPath(arrDou);
            });
        });
        baiduMapInfo.setResult(result);

        return baiduMapInfo;*/
    }

    /**
     * 路线规划-骑行
     *
     * @param origin
     * @param destination
     * @param coord_type
     * @return
     */
    public BaiduMapInfo<Result> riding(String origin, String destination, String coord_type) {
        String[] originStr = origin.split(",");
        String[] destinationStr = destination.split(",");
        double[] originBD09 = CoordinateConvert.wgs2BD09(Double.parseDouble(originStr[0]), Double.parseDouble(originStr[1]));
        double[] destinationBD09 = CoordinateConvert.wgs2BD09(Double.parseDouble(destinationStr[0]), Double.parseDouble(destinationStr[1]));
        String orginJoin = ArrayUtil.join(originBD09, ",");
        String destinationJoin = ArrayUtil.join(destinationBD09, ",");
        Map<String, Object> paramsMap = new HashMap<>(4);
        paramsMap.put("ak", ak);
        paramsMap.put("origin", orginJoin);
        paramsMap.put("destination", destinationJoin);
        paramsMap.put("coordType", "bd09ll");
        String drivingResultStr = restTemplate.getForObject(TRACK_ADDRESS + "riding?origin={origin}&destination={destination}&ak={ak}&coord_type={coordType}", String.class, paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(drivingResultStr, BaiduMapInfo.class);

        if (baiduMapInfo.getStatus() != 0) {
            throw new ForestBaseException("路线规划-骑行出错");
        }

        JSONObject jsonResult = (JSONObject) baiduMapInfo.getResult();
        Result result = JSON.toJavaObject(jsonResult, Result.class);
        result.getRoutes().forEach(routes -> {
            routes.getSteps().forEach(steps -> {
                ArrayList<double[]> arrDou = new ArrayList<>();
                List<String> arr = Arrays.asList(steps.getPath().toString().split(";"));
                arr.forEach(s -> {
                    String[] split = s.split(",");
                    //经度 ,纬度
                    double[] bd092WGS = CoordinateConvert.bd092WGS(Double.parseDouble(split[1]), Double.parseDouble(split[0]));
                    double[] lonlatWGS = {bd092WGS[1], bd092WGS[0]};
                    arrDou.add(lonlatWGS);
                });
                steps.setPath(arrDou);
            });
        });
        baiduMapInfo.setResult(result);

        return baiduMapInfo;


       /* Map<String,Object> paramsMap = new HashMap<>(4);
        paramsMap.put("ak",ak);
        paramsMap.put("origin",origin);
        paramsMap.put("destination",destination);
        paramsMap.put("coordType",coord_type);
        String ridingResultStr = restTemplate.getForObject(TRACK_ADDRESS + "riding?origin={origin}&destination={destination}&ak={ak}&coord_type={coordType}", String.class, paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(ridingResultStr, BaiduMapInfo.class);

        if(baiduMapInfo.getStatus()!=0){
            throw new ForestBaseException("路线规划-骑行出错");
        }
        JSONObject jsonResult = (JSONObject) baiduMapInfo.getResult();
        Result result = JSON.toJavaObject(jsonResult, Result.class);

        result.getRoutes().forEach(routes -> {
            routes.getSteps().forEach(steps -> {
                ArrayList<double[]> arrDou = new ArrayList<>();
                List<String> arr = Arrays.asList(steps.getPath().toString().split(";"));
                arr.forEach(s -> {
                    String[] split = s.split(",");
                    //经度 ,纬度
                    double[] a = {Double.parseDouble(split[0]),Double.parseDouble(split[1]) };
                    arrDou.add(a);
                });
                List<double[]> lists = LongitudeLatitudeTransisteUtils.bd09_To_gps84Array(arrDou);
                steps.setPath(lists);
            });
        });
        baiduMapInfo.setResult(result);
        return baiduMapInfo;*/
    }

    /**
     * 路线规划-步行
     *
     * @param origin
     * @param destination
     * @param coord_type
     * @return
     */
    public BaiduMapInfo<Result> walking(String origin, String destination, String coord_type) {
        String[] originStr = origin.split(",");
        String[] destinationStr = destination.split(",");
        double[] originBD09 = CoordinateConvert.wgs2BD09(Double.parseDouble(originStr[0]), Double.parseDouble(originStr[1]));
        double[] destinationBD09 = CoordinateConvert.wgs2BD09(Double.parseDouble(destinationStr[0]), Double.parseDouble(destinationStr[1]));
        String orginJoin = ArrayUtil.join(originBD09, ",");
        String destinationJoin = ArrayUtil.join(destinationBD09, ",");
        Map<String, Object> paramsMap = new HashMap<>(4);
        paramsMap.put("ak", ak);
        paramsMap.put("origin", orginJoin);
        paramsMap.put("destination", destinationJoin);
        paramsMap.put("coordType", "bd09ll");
        String drivingResultStr = restTemplate.getForObject(TRACK_ADDRESS + "walking?origin={origin}&destination={destination}&ak={ak}&coord_type={coordType}", String.class, paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(drivingResultStr, BaiduMapInfo.class);

        if (baiduMapInfo.getStatus() != 0) {
            throw new ForestBaseException("路线规划-步行出错");
        }

        JSONObject jsonResult = (JSONObject) baiduMapInfo.getResult();
        Result result = JSON.toJavaObject(jsonResult, Result.class);
        result.getRoutes().forEach(routes -> {
            routes.getSteps().forEach(steps -> {
                ArrayList<double[]> arrDou = new ArrayList<>();
                List<String> arr = Arrays.asList(steps.getPath().toString().split(";"));
                arr.forEach(s -> {
                    String[] split = s.split(",");
                    //经度 ,纬度
                    double[] bd092WGS = CoordinateConvert.bd092WGS(Double.parseDouble(split[1]), Double.parseDouble(split[0]));
                    double[] lonlatWGS = {bd092WGS[1], bd092WGS[0]};
                    arrDou.add(lonlatWGS);
                });
                steps.setPath(arrDou);
            });
        });
        baiduMapInfo.setResult(result);

        return baiduMapInfo;
        /*Map<String,Object> paramsMap = new HashMap<>(4);
        paramsMap.put("ak",ak);
        paramsMap.put("origin",origin);
        paramsMap.put("destination",destination);
        paramsMap.put("coordType",coord_type);
        String walkingResultStr  = restTemplate.getForObject(TRACK_ADDRESS + "walking?origin={origin}&destination={destination}&ak={ak}&coord_type={coordType}", String.class, paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(walkingResultStr, BaiduMapInfo.class);

        if(baiduMapInfo.getStatus()!=0){
            throw new ForestBaseException("路线规划-步行出错");
        }

        JSONObject jsonResult = (JSONObject) baiduMapInfo.getResult();
        Result result = JSON.toJavaObject(jsonResult, Result.class);

        result.getRoutes().forEach(routes -> {
            routes.getSteps().forEach(steps -> {
                ArrayList<double[]> arrDou = new ArrayList<>();
                List<String> arr = Arrays.asList(steps.getPath().toString().split(";"));
                arr.forEach(s -> {
                    String[] split = s.split(",");
                    //经度 ,纬度
                    double[] a = {Double.parseDouble(split[0]),Double.parseDouble(split[1]) };
                    arrDou.add(a);
                });
                List<double[]> lists = LongitudeLatitudeTransisteUtils.bd09_To_gps84Array(arrDou);
                steps.setPath(lists);
            });
        });
        baiduMapInfo.setResult(result);
        return baiduMapInfo;*/
    }

    /**
     * 地址查询
     *
     * @param query    关键字
     * @param province 省
     * @param region   城市 南京市
     * @param county   浦口区
     *
     * @return
     */
    public BaiduMapInfo<List<AddressResult>> promptAddress(String query, String province, String region, String county,
                                                           String coordType, boolean cityLimit)
            throws UnsupportedEncodingException {
        //目前缺少查询省对应城市的数据库数据,暂无法根据省份查询 TODO
        Map<String, Object> paramsMap = new HashMap<>(6);
        paramsMap.put("query", query);
        paramsMap.put("region", region);
        paramsMap.put("coordType", "bd09ll");
        paramsMap.put("cityLimit", cityLimit);
        paramsMap.put("output", "json");
        paramsMap.put("ak", ak);

        String promptAddressStr = restTemplate.getForObject(PROMPT_ADDRESS
                        + "suggestion?query={query}&region={region}&city_limit={cityLimit}&output={output}&coord_type={coordType}&ak={ak}",
                String.class, paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(promptAddressStr, BaiduMapInfo.class);
        if (baiduMapInfo.getStatus() != 0) {
            throw new ForestBaseException("地址查询出错");
        }
        JSONArray jsonArray = (JSONArray) baiduMapInfo.getResult();
        List<AddressResult> addressResultList = jsonArray.toJavaList(AddressResult.class);
        List<AddressResult> countyAddressResult = addressResultList;
        if (!StringUtils.isEmpty(county)) {
            countyAddressResult = addressResultList.stream().filter(
                    addressResult -> county.equals(addressResult.getDistrict())).collect(Collectors.toList());
        }
        // 过滤无具体经纬度的百度数据
        countyAddressResult = countyAddressResult.stream().filter(e -> e.getLocation() != null).collect(Collectors.toList());
        countyAddressResult
//                .stream().filter(e-> e.getLocation() != null)
                .forEach(addressResult -> {
                    Destination location = addressResult.getLocation();
                    double[] bd092WGS = CoordinateConvert.bd092WGS(location.getLat(), location.getLng());
                    location.setLat(bd092WGS[0]);
                    location.setLng(bd092WGS[1]);
                    addressResult.setLocation(location);
                });

        baiduMapInfo.setResult(countyAddressResult);
        return baiduMapInfo;
        /*//目前缺少查询省对应城市的数据库数据,暂无法根据省份查询 TODO
        Map<String,Object> paramsMap = new HashMap<>(6);
        paramsMap.put("query",query);
        paramsMap.put("region",region);
        paramsMap.put("coordType","bd09ll");
        paramsMap.put("cityLimit",true);
        paramsMap.put("output","json");
        paramsMap.put("ak",ak);

        String promptAddressStr=restTemplate.getForObject(PROMPT_ADDRESS+"suggestion?query={query}&region={region}&city_limit={cityLimit}&output={output}&coord_type={coordType}&ak={ak}",String.class,paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(promptAddressStr, BaiduMapInfo.class);
        if(baiduMapInfo.getStatus()!=0){
            throw new ForestBaseException("地址查询出错");
        }
        if(!StringUtils.isEmpty(county)) {
            JSONArray jsonArray = (JSONArray) baiduMapInfo.getResult();
            List<AddressResult> addressResultList = jsonArray.toJavaList(AddressResult.class);
//            List<AddressResult> countyAddressResult =  addressResultList.stream().filter(addressResult -> county.equals(addressResult.getDistrict())).collect(Collectors.toList());
            List<AddressResult> countyAddressResult =  addressResultList.stream().filter(addressResult -> county.equals(addressResult.getDistrict())).collect(Collectors.toList());
            countyAddressResult.forEach(addressResult -> {
                Destination location = addressResult.getLocation();

                double[] bd092WGS = CoordinateConvert.bd092WGS(location.getLat(), location.getLng());
                location.setLat(bd092WGS[0]);
                location.setLng(bd092WGS[1]);
                addressResult.setLocation(location);
            });
            baiduMapInfo.setResult(countyAddressResult);
        }
        return baiduMapInfo;*/
    }

    /**
     * poi检索
     *
     * @param query
     * @param region
     * @param coordType
     * @return
     * @throws UnsupportedEncodingException
     */
    public POIMapInfo poiMapInfo(String query, String region, String coordType) throws UnsupportedEncodingException {
        Map<String, Object> paramsMap = new HashMap<>(6);
        paramsMap.put("query", query);
        paramsMap.put("region", region);
        paramsMap.put("coordType", "bd09ll");
        paramsMap.put("cityLimit", true);
        paramsMap.put("output", "json");
        paramsMap.put("ak", ak);

        String searchAddressStr = restTemplate.getForObject(PROMPT_ADDRESS + "search?query={query}&region={region}&city_limit={cityLimit}&output={output}&coord_type={coordType}&ak={ak}", String.class, paramsMap);
        POIMapInfo poiMapInfo = JSON.parseObject(searchAddressStr, POIMapInfo.class);
        poiMapInfo.getResults().stream().forEach(addressResult -> {
            Destination location = addressResult.getLocation();

            double[] bd092WGS = CoordinateConvert.bd092WGS(location.getLat(), location.getLng());
            location.setLat(bd092WGS[0]);
            location.setLng(bd092WGS[1]);
            addressResult.setLocation(location);
        });
        if (poiMapInfo.getStatus() != 0) {
            throw new ForestBaseException("地址检索出错");
        }
        return poiMapInfo;
        /*Map<String,Object> paramsMap = new HashMap<>(6);
        paramsMap.put("query",query);
        paramsMap.put("region",region);
        paramsMap.put("coordType",coordType);
        paramsMap.put("cityLimit",true);
        paramsMap.put("output","json");
        paramsMap.put("ak",ak);

        String searchAddressStr=restTemplate.getForObject(PROMPT_ADDRESS+"search?query={query}&region={region}&city_limit={cityLimit}&output={output}&coord_type={coordType}&ak={ak}",String.class,paramsMap);
        POIMapInfo poiMapInfo = JSON.parseObject(searchAddressStr, POIMapInfo.class);
        if(poiMapInfo.getStatus()!=0){
            throw new ForestBaseException("地址检索出错");
        }
        return poiMapInfo;*/
    }

    /**
     * 地点详情
     *
     * @param uid
     * @return
     */
    public BaiduMapInfo<DetailAddressResult> getDetailAddress(String uid) {
        Map<String, Object> paramsMap = new HashMap<>(6);
        paramsMap.put("uid", uid);
        paramsMap.put("output", "json");
        paramsMap.put("scope", 2);
        paramsMap.put("ak", ak);

        String detailAddressStr = restTemplate.getForObject(PROMPT_ADDRESS + "detail?uid={uid}&output={output}&scope={scope}&ak={ak}", String.class, paramsMap);
        BaiduMapInfo baiduMapInfo = JSON.parseObject(detailAddressStr, BaiduMapInfo.class);
        if (baiduMapInfo.getStatus() != 0) {
            throw new ForestBaseException("详细地址检索异常");
        }
        return baiduMapInfo;
    }

    /**
     * 根据经纬度查询详细地点
     */
    public String queryAddressByLaAndLo(String longitude, String latitude) {

        Map<String, Object> paramsMap = new HashMap<>(6);
        paramsMap.put("ak", ak);
        paramsMap.put("output", "json");
        paramsMap.put("location", latitude + "," + longitude);
        String detailAddress = restTemplate.getForObject(
                DETAIL_ADDRESS + "?location={location}&output={output}&ak={ak}", String.class, paramsMap);
        return detailAddress;
    }

    public Map<String, String> geocoding(String address) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("ak", ak);
        paramsMap.put("output", "json");
        paramsMap.put("address", address);

        String detailAddressStr = restTemplate.getForObject(
                GEOCODING + "?address={address}&output={output}&ak={ak}", String.class, paramsMap);
        Map<String, Object> resultMap = JSON.parseObject(detailAddressStr, Map.class);
        Validate.isTrue(MapUtils.getIntValue(resultMap, "status") == 0);

        Map<String, Object> result = JSON.parseObject(MapUtil.getStr(resultMap, "result"), Map.class);

        Map<String, String> location = JSON.parseObject(MapUtil.getStr(result, "location"), Map.class);

        return location;
    }

}
